/************************************************************************************************
 * @name    SequenceList.c
 * @brief   这是顺序表的代码案例，主要学习顺序表的数据元素的增删改查，并设计API接口
 * @date    2024/12/24
 * @anchor  boluzs@163.com
 * @note    None
 * @version 1.0.0
 *
 * 版权声明
 * CopyRight (c)   2024-2025   boluzs@163.com    All Right Reciver
 *
 *************************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
typedef int DataType_t; // 用于说明顺序表数据元素的类型 提高程序的可移植性

typedef struct SequenceList
{
    unsigned int Size; // 用于记录顺序表的容量
    DataType_t *Addr;  // 用于记录顺序表的起始地址
    int Last;          // 用于记录顺序表中最后一个有效元素的下标 可为-1
} SqList_t, *SqList_p;

/************************************************************************************************
 *       @name   SqList_Create
 *       @brief  创建顺序表
 *       @param  Size: 指顺序表的容量
 *       @note   None
 *       @retval 函数调用成功，返回指向SqlList_t类型的指针
 *************************************************************************************************/
SqList_p SqList_Create(unsigned int Size)
{
    // 1.为管理顺序表的结构体申请堆内存并做错误处理
    // calloc函数返回一个void*类型的指针;
    SqList_p Pmanager = (SqList_p)calloc(1, sizeof(SqList_t));
    if (NULL == Pmanager)
    {
        // perror("Calloc For SqList_t Error");
        fprintf(stderr, "Calloc For SqList_t Error,errno = %d,%s\n", errno, strerror(errno));
        exit(-1); // 导致程序终止
    }

    // 2.为顺序表的数据元素申请堆内存，并进行错误处理
    DataType_t *Padder = (DataType_t *)calloc(Size, sizeof(DataType_t));
    if (NULL == Padder)
    {
        // perror("Calloc For SqList_t Error");
        fprintf(stderr, "Calloc For Data Element Error,errno = %d,%s\n", errno, strerror(errno));
        exit(-1); // 导致程序终止
    }

    // 3.需要对顺序表的管理结构体成员进行赋值
    Pmanager->Size = Size;   // 记录容量
    Pmanager->Last = -1;     // 记录下标
    Pmanager->Addr = Padder; // 记录地址

    // 4.返回地址，并输出调试信息
    printf("SequenceList Create Successfully!\n");
    return Pmanager;
};

/************************************************************************************************
 *       @name   SqList_IsFull
 *       @brief  判断顺序表是否已满
 *       @param  Pmanager: 指记录顺序表属性的结构体指针
 *       @note   None
 *       @retval 顺序表已满，返回true，顺序表已满，返回false
 *************************************************************************************************/
bool SqList_IsFull(SqList_p Pmanager)
{
    return (Pmanager->Last == Pmanager->Size - 1) ? true : false;
}

/************************************************************************************************
 *       @name   SqList_IsEmpty
 *       @brief  判断顺序表是否已满
 *       @param  Pmanager: 指记录顺序表属性的结构体指针
 *       @note   None
 *       @retval 顺序表为空，返回true，顺序表不为空，返回false
 *************************************************************************************************/
bool SqList_IsEmpty(SqList_p Pmanager)
{
    return (Pmanager->Last == -1) ? true : false;
}

/************************************************************************************************
 *       @name   SqList_TailInsert
 *       @brief  向顺序表的尾部插入新元素
 *       @param  Pmanager: 指记录顺序表属性的结构体指针
 *       @param  Data: 指待插入顺序表的数据元素的值
 *       @note   插入元素之前需要先检查顺序表是否已满
 *       @retval 插入成功，返回true，插入失败，返回false
 *************************************************************************************************/
bool SqList_TailInsert(SqList_p Pmanager, DataType_t Data)
{
    // 为了提高程序的可靠性，所以需要对指针进行备份
    SqList_p P = Pmanager;

    // 1、检查参数有效性
    if (NULL == Pmanager)
    {
        fprintf(stderr, "Insert Error, Argument Is Invalid\n");
        return false;
    }

    // 2、检查顺序表容量
    if (SqList_IsFull(P))
    {
        fprintf(stderr, "Insert Error, SqList Is Full\n");
        return false;
    }

    // 3、顺序表插入元素
    Pmanager->Addr[Pmanager->Last + 1] = Data;

    // 4、更新顺序表的属性
    Pmanager->Last++;
    return true;
}

/************************************************************************************************
 *       @name   SqList_TailDelete
 *       @brief  删除顺序表的尾部元素
 *       @param  Pmanager: 指记录顺序表属性的结构体指针
 *       @note   删除元素之前需要先检查顺序表是否为空
 *       @retval 删除成功，返回true，删除失败，返回false
 *************************************************************************************************/
bool SqList_TailDelete(SqList_p Pmanager)
{
    // 为了提高程序的可靠性，所以需要对指针进行备份
    SqList_p P = Pmanager;

    // 1、检查参数有效性
    if (NULL == Pmanager)
    {
        fprintf(stderr, "Delete Error, Argument Is Invalid\n");
        return false;
    }

    // 2、检查顺序表容量
    if (SqList_IsEmpty(P))
    {
        fprintf(stderr, "Delete Error, SqList Is Empty\n");
        return false;
    }

    // 3、更新顺序表的下标
    P->Last--;

    return true;
}

/************************************************************************************************
 *       @name   SqList_Print
 *       @brief  遍历顺序表
 *       @param  Pmanager: 指记录顺序表属性的结构体指针
 *       @note   None
 *       @retval 遍历成功，返回true，遍历失败，返回false
 *************************************************************************************************/
bool SqList_Print(SqList_p Pmanager)
{
    // 为了提高程序的可靠性，所以需要对指针进行备份
    SqList_p P = Pmanager;

    // 1、检查参数有效性
    if (NULL == Pmanager)
    {
        fprintf(stderr, "Print Error, Argument Is Invalid\n");
        return false;
    }

    // 2、对顺序表的元素进行遍历
    for (int i = 0; i <= P->Last; i++)
    {
        printf("SqList Element[%d] = %d\n", i, P->Addr[i]);
    }
    return true;
}

/************************************************************************************************
 *       @name   SqList_Distory
 *       @brief  释放顺序表内存以及元素内存
 *       @param  Pmanager: 指记录顺序表属性的结构体指针
 *       @param  Paddr: 指记录顺序表里面元素的指针
 *       @note   None
 *       @retval 函数调用成功，返回true，调用失败，返回false
 *************************************************************************************************/
bool SqList_Destory(SqList_p Pmanager, DataType_t * Paddr)
{
    // 备份指针
    SqList_p P = Pmanager;

    // 1.释放顺序表的堆内存
    free(Pmanager);
    free(Paddr);
    // 2.释放顺序表的数据元素的堆内存
    return true;
};

/**
 * @name:   main
 * @brief:  主函数
 * @param   None
 * @note:   None
 * @retval: 调用成功，返回0，调用失败，返回-1
 */
int main(int argc, char const *argv[])
{
    // 1、创建顺序表
    SqList_p sq_list_p = SqList_Create(3);
    // 2、向尾部插入元素
    SqList_TailInsert(sq_list_p, 1);
    SqList_TailInsert(sq_list_p, 3);
    SqList_TailInsert(sq_list_p, 5);
    SqList_TailInsert(sq_list_p, 7);
    SqList_TailInsert(sq_list_p, 9);
    // 4、遍历顺序表
    printf("---------------------------------\n");
    SqList_Print(sq_list_p);
    // 5、删除尾部元素
    SqList_TailDelete(sq_list_p);
    // 6、遍历顺序表
    printf("---------------------------------\n");
    SqList_Print(sq_list_p);
    // 7、释放内存
    SqList_Destory(sq_list_p, sq_list_p->Addr);
    return 0;
}
